﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core;
using Cofe.Core.Interfaces;
using Cofe.Core.Property;
using Cofe.Core.Utils;

namespace Cofe.Media
{
    public class ImagePropertyProvider : PropertyProviderBase<IPropertyHost>
    {
        private static Size thumbnailSize = new Size(160, 108);

        #region Constructor

        internal ImagePropertyProvider(IPropertyHost propertyHost)
            : base(propertyHost,
            Cofe.Media.PropertyDefinitions.MediaPropDefinitions,
            Cofe.Media.PropertyDefinitions.ExifPropDefinitions)
        {
            _additionalSupportedProperties.Add(CofeMediaProperties.Width);
            _additionalSupportedProperties.Add(CofeMediaProperties.Height);
            _additionalSupportedProperties.Add(CofeMediaProperties.FullThumbnail);
            registerActionAsync<BitmapContainer>(CofeMediaProperties.GetThumbnailAsync, (pd) => getThumbnailAsync(pd));
        }

        #endregion

        #region Methods

        private async Task<BitmapContainer> getThumbnailAsync(ParameterDic pd)
        {
            int height = pd.ContainsKey("Height") ? Int32.Parse(pd["Height"] as string) : -1;
            int width = pd.ContainsKey("Width") ? Int32.Parse(pd["Width"] as string) : -1;

            Bitmap baseBitmap = null;

            if (width <= thumbnailSize.Width && height <= thumbnailSize.Height)
            {
                byte[] thumbnail = await Entity.Behaviors.GetPropertyAsync<byte[]>(CofeMediaProperties.FullThumbnail);
                if (thumbnail != null && thumbnail.Length > 0)
                {
                    var ms = new MemoryStream(thumbnail);
                    baseBitmap = new Bitmap(ms);
                }
            }

            if (baseBitmap == null)
            {
                using (var stream = await Entity.OpenStreamAsync(true, false))
                    baseBitmap = new Bitmap(stream.Stream);
            }

            baseBitmap = BitmapUtils.EnsureBitmapSize(baseBitmap, new Size(width, height));

            return BitmapContainer.FromBitmap(baseBitmap);
        }

        protected void loadFromImage(StreamContainer stream, Dictionary<object, PropertyPair> updateList)
        {
            using (Bitmap bitmap = new Bitmap(stream.Stream))
            {
                updateList.AddOrUpdate(CofeMediaProperties.Width,
                    PropertyPair.FromValue(CofeMediaProperties.Width, bitmap.Width));

                updateList.AddOrUpdate(CofeMediaProperties.Height,
                    PropertyPair.FromValue(CofeMediaProperties.Height, bitmap.Height));

                using (var thumbnail = bitmap.GetThumbnailImage(thumbnailSize.Width, thumbnailSize.Height, null, IntPtr.Zero))
                    updateList.AddOrUpdate(CofeMediaProperties.FullThumbnail,
                        PropertyPair.FromValue(CofeMediaProperties.FullThumbnail, thumbnail.ToByteArray()));
            }
        }

        public override async Task<PropertyPair[]> GetPropertyAsync(object property)
        {
            if (property.Equals(CofeMediaProperties.FullThumbnail) ||
                property.Equals(CofeMediaProperties.Height) ||
                property.Equals(CofeMediaProperties.Width) ||
                Cofe.Media.PropertyDefinitions.ExifPropDefinitions.IsPropertySupported(property))
            {
                try
                {
                    Dictionary<object, PropertyPair> dic = new Dictionary<object, PropertyPair>();
                    using (var stream = await Entity.OpenStreamAsync(true, false))
                    {
                        loadFromImage(stream, dic);
                        return dic.Values.ToArray();
                    }
                }
                catch (Exception ex)
                {
                    return null;
                }
            }

            return await base.GetPropertyAsync(property);
        }

        #endregion

        #region Data

        #endregion

        #region Public Properties

        #endregion
    }
}
